from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse
from jose import jwt, JWTError
from config import settings
import logging
from service.commonService import CommonService


logger = logging.getLogger(__name__)

common_service = CommonService()


class AuthMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)
        # 白名单路径列表，这些路径不需要token验证
        self.white_list = [
            ("/api/login", "POST"),  # 登录接口
            ("/api/captchaImage", "GET"),  # 验证码接口
            ("/docs", "GET"),  # Swagger UI
            ("/docs/oauth2-redirect", "GET"),  # Swagger OAuth redirect
            ("/openapi.json", "GET"),  # OpenAPI schema
            ("/redoc", "GET"),  # ReDoc UI
        ]

    def is_path_in_whitelist(self, path: str, method: str) -> bool:
        """
        检查请求路径是否在白名单中
        """
        # 记录请求信息
        logger.info(f"Checking path: {path}, method: {method}")

        # 去除查询参数
        path = path.split('?')[0]

        # Swagger UI 相关路径
        swagger_paths = [
            '/docs',
            '/docs/',
            '/openapi.json',
            f'{settings.API_STR}/openapi.json',
            '/swagger-ui.css',
            '/swagger-ui-bundle.js',
            '/swagger-ui-standalone-preset.js',
            '/favicon.ico'
        ]

        # 如果是 Swagger 相关路径，允许通过
        if path in swagger_paths:
            return True

        # 如果路径以 /docs/ 开头，允许通过
        if path.startswith('/docs/'):
            return True

        # 检查完整的路径和方法是否匹配
        is_allowed = (path, method) in self.white_list
        return is_allowed

    async def dispatch(self, request: Request, call_next):
        # 检查是否在白名单中
        if self.is_path_in_whitelist(request.url.path, request.method):
            return await call_next(request)

        # 获取token
        token = request.headers.get("Authorization")
        if not token:
            return JSONResponse(
                status_code=200,
                content={
                    "code": 401,
                    "msg": "登录认证失败",
                    "data": None
                }
            )

        if token.startswith("Bearer "):
            token = token[7:]

        if common_service.is_token_blacklisted(token):
            logger.error(f"Token validation error: is_token_blacklisted")
            return JSONResponse(
                status_code=200,
                content={
                    "code": 401,
                    "msg": "无效的token或token已过期",
                    "data": None
                }
            )

        try:
            # 验证token
            payload = jwt.decode(
                token,
                settings.SECRET_KEY,
                algorithms=["HS256"]
            )

            # 将用户信息添加到request的state中，供后续使用
            request.state.user = payload
            request.state.token = token

            # 继续处理请求
            response = await call_next(request)
            return response

        except JWTError as e:
            logger.error(f"Token validation error: {str(e)}")
            return JSONResponse(
                status_code=200,
                content={
                    "code": 401,
                    "msg": "无效的token或token已过期",
                    "data": None
                }
            )
        except Exception as e:
            logger.error(f"Auth middleware error: {str(e)}")
            return JSONResponse(
                status_code=200,
                content={
                    "code": 500,
                    "msg": "服务器内部错误",
                    "data": None
                }
            )
